"""
    Contoller for viewing and editing students records.
"""

import operator

from decimal import Decimal
from datetime import date
from cherrypy import request
from turbogears import expose, redirect, validate, identity, validators, widgets
from pytils.translit import translify

from mnemoply import model
from mnemoply.utils import LocalMenuItem, MonthYear, Wrapper, getDocumentType
from mnemoply.mass_actions import MassAction, MassActionForm
from mnemoply.preorders import preorders
from mnemoply.controllers.lookup import LookupController, LookupControllerBase, TableCol, TableLookupDataSource
from mnemoply.controllers.crud import CRUDController, ItemActionsTab, ItemTab
from mnemoply.widgets import DictionaryField, YearField, FieldGroup, GroupField, column_widget, fields_for

class MATransformToPartner(MassAction):
    target_class = model.Student
    name = "transform_to_partner"
    title = _("Transform to partner")

    def call(self, objs):
        p_type = model.PartnerType.get(2)  # FIXME
        office = identity.current.user.office
        for o in objs:
            model.Partner(
                partnerType=p_type,
                surname=o.surname,
                forename=o.forename,
                patronymic=o.patronymic,
                email=o.email,
                password=model.Partner.createNewPassword(office),
                office=office
                )

class MATransliterateName(MassAction):
    target_class = model.Student
    name = "transliterate_name"
    title = _("Transliterate name")
    form = MassActionForm(name=name, fields=[])

    def call(self, students):
        for s in students:
            s.surname_translit = translify(s.surname)
            s.forename_translit = translify(s.forename)
            s.patronymic_translit = translify(s.patronymic)

class MAIncrementSchoolForm(MassAction):
    target_class = model.Student
    name = "increment_school_form"
    title = _("Increment schoor form")

    def call(self, students):
        for s in students:
            s.schoolForm += 1

class MAGroupInclusion(MassAction):
    target_class = model.Student
    name = "group_inclusion"
    title = _("Group inclusion")

    form = MassActionForm(name=name,
        fields=[
            DictionaryField(
                name="preorder_id",
                model_object_name='Preorder',
                empty_caption=_("*New preorder*"),
                records=lambda: model.Preorder.selectByPTypeTag('GroupInclusion'),
                label=_("Preorder"),
            ),
            GroupField(
                name="group_id",
                not_empty=True,
                label="In group",
            ),
            column_widget(model.Transfer.sqlmeta.columns.get('comment')),
        ]
    )

    @identity.require(identity.has_any_permission('dba', 'Order:GroupInclusion'))
    def call(self, objs, preorder_id, group_id, comment):
        group = model.Group.get(int(group_id))

        preorder = preorders.create_or_get(preorder_id, 'GroupInclusion')

        for x in objs:
            preorder.add(student=x, group=group, comment=comment)

        raise redirect("/Preorder/%d/" % preorder.obj.id)

class MACreateFinalDocument(MassAction):
    target_class = model.Student
    title = _("Final document")
    name = "final_document"

    form = MassActionForm(name=name,
        fields=[
            DictionaryField(
                name="specialization_id",
                model_object_name='Specialization',
                not_empty=True,
                label=_("Specialization"),
            ),
            DictionaryField(
                name="qualification_id",
                model_object_name='Qualification',
                not_empty=True,
                label=_("Qualification"),
            ),
            DictionaryField(
                name="organization_id",
                model_object_name='Organization',
                not_empty=True,
                label=_("Organization"),
            ),
            widgets.CalendarDatePicker(
                label=_('Creation date'),
                name='date',
                calendar_lang='ru',
                format='%d.%m.%Y',
                validator=validators.DateTimeConverter(format="%d.%m.%Y")),
            widgets.CalendarDatePicker(
                label=_('Defence date'),
                name='defence_date',
                calendar_lang='ru',
                format='%d.%m.%Y',
                validator=validators.DateTimeConverter(format="%d.%m.%Y")),
            YearField(name='start_year', not_empty=True, label=_("Start year")),
            YearField(name='end_year', not_empty=True, label=_("End year")),
        ]
    )

    def call(self, objs, specialization_id, qualification_id, organization_id, date, defence_date, start_year, end_year):
        specialization = model.Specialization.get(specialization_id)
        qualification = model.Qualification.get(qualification_id)
        organization = model.Organization.get(organization_id)

        for s in objs:
            (document, hours, works_amount, last_final_topic) = getDocumentType(s)

            if document is None:
                continue

            number = None
            office = identity.current.user.office

            if office:
                number = model.DocumentNumber.getNewOrdinal(office)
            else:
                continue

            owner = model.Person.get(1)  # -.-.- person
            if identity.current.user.person:
                owner = identity.current.user.person

            model.FinalDocument(
                student=s,
                yearBegin=start_year,
                yearEnd=end_year,
                hours=hours,
                works=works_amount,
                owner=owner,
                lastTopic=last_final_topic,
                number=number,
                documentType=document,
                creationDate=date,
                defenceDate=defence_date,
                qualification=qualification,
                specialization=specialization,
                organization=organization,
                )

class MACreateTemporaryPaymentRecords(MassAction):
    target_class = model.Student
    name = "create_temporary_records"
    title = _("Create temporary payment records")

    form = MassActionForm(name=name,
        fields=[
            DictionaryField(
                    name="organization_id",
                    model_object_name='Organization',
                    not_empty=True,
                    label=_("Organization")),
            DictionaryField(
                    name="trend_id",
                    model_object_name='Trend',
                    not_empty=True,
                    label=_("Trend"))
            ])

    def call(self, objs, organization_id, trend_id):
        organization = model.Organization.get(int(organization_id))
        trend = model.Trend.get(int(trend_id))
        information_source = model.InformationSource.byStringId('our_student')
        
        for s in objs:
            model.TemporaryPaymentRecord(
                student=s,
                organization=organization,
                trend=trend,
                tempSurname=s.surname,
                tempForename=s.forename,
                tempPatronymic=s.patronymic,
                informationSource=information_source,
                phone=", ".join(set([a.customer.phone for a in (model.StudentAgreement.selectBy(student=s))])),
                register=None,
            )

class MigrationsItemTab(ItemTab):
    title = _("Migrations")
    name = "migrations_tab"
    template = "../student_migrations_tab"

class MarksItemTab(ItemActionsTab):
    title = _("Marks")
    name = "marks_tab"
    ma_class_name = 'Mark'

    def getRecords(self, obj):
        marks = list(model.Mark.selectBy(student=obj))
        marks.sort(key=lambda x: x.date)
        return marks

    def getRecordTitle(self, obj):
        return "%s: %s" % (obj.topic.title, obj.markType.title)

class StudentsInGroupItemTab(ItemActionsTab):
    title = _("Students-In-Group")
    name = "students_in_group_tab"
    ma_class_name = 'StudentInGroup'

    def getRecords(self, obj):
        sigs = list(model.StudentInGroup.selectBy(student=obj))
        sigs.sort(key=lambda x: x.title)
        return sigs

    def getRecordTitle(self, obj):
        return obj.group.title

class AgreementItemTab(ItemActionsTab):
    title = _("Agreements")
    name = "agreements_tab"
    ma_class_name = 'StudentAgreement'

    def getRecords(self, obj):
        agrs = list(model.StudentAgreement.selectBy(student=obj))
        agrs.sort(key=lambda x: x.title)
        return agrs

    def getRecordTitle(self, obj):
        return obj.title

class PaymentItemTab(ItemActionsTab):
    title = _("Payment record")
    name = "payment_record_tab"
    ma_class_name = 'PaymentRecord'

    def getRecords(self, obj):
        prs = list(model.PaymentRecord.selectBy(student=obj))
        prs.sort(key=lambda x: x.title)
        return prs

    def getRecordTitle(self, obj):
        return obj.title

class DiscontCardTab(ItemTab):
    title = _("Discont card")
    name = "discont_card_tab"
    template = "../student_discont_card_tab"
    edit_widget = None

    edit_fields = [
        'number',
        'comment',
        ]

    save_action = 'save_info'
    save_action_text = _("Save")
    add_action = 'add_info'
    add_action_text = _("Add")

    def __init__(self):
        self.edit_fields = [FieldGroup(fields=self.edit_fields)]
        self.edit_widget = widgets.TableForm(fields=fields_for(model.DiscontCard, self.edit_fields))

    def setting_form(self):
        return self.edit_widget

    @identity.require(identity.has_any_permission('dba', 'Student/edit'))
    @validate(form=setting_form)
    @expose()
    def save_info(self, obj, tg_errors=None, **data ):
        if tg_errors:
            return self.controller.show(obj)

        info = model.DiscontCard.selectBy(student=obj)
        if len(list(info)):
            info = model.DiscontCard.selectBy(student=obj)[0]
            info.set(**data)

        raise redirect("./")
    save_info.expose_object = True

    @identity.require(identity.has_any_permission('dba', 'Student/edit'))
    @validate(form=setting_form)
    @expose()
    def add_info(self, obj, tg_errors=None, **data ):
        if tg_errors:
            return self.controller.show(obj)

        info = model.DiscontCard.selectBy(student=obj)
        if not len(list(info)):
            data["studentID"] = unicode(obj.id)
            model.DiscontCard(**data)

        raise redirect("./")
    save_info.expose_object = True

class StudentController(LookupController, CRUDController):
    lookup_columns = [
            TableCol(name='cache_groups', caption=_('Groups'), size=10),

            TableCol(name='surname', caption=_('Surname'), size=10),
            TableCol(name='forename', caption=_('Forename'), size=10),
            TableCol(name='patronymic', caption=_('Patronymic'), size=10, hidden=True),
            TableCol(name='birthday', caption=_('Birthday'),
                validator=validators.Int(), size=4, hidden=True),

            TableCol(name='cache_in_groups', caption=_('Groups count'), hidden=True,
                validator=validators.Int(), size=4),
           # TableCol(name='cache_balance', caption=_('Balance'), hidden=True,validator=validators.Number(), size=10),
            TableCol(name='last_year_group', caption=_('Last year group'), hidden=True),

            TableCol(name='email', caption=_('E-mail'), hidden=True, size=9),
            TableCol(name='gender_str', caption=_('Gender'), hidden=True, size=4),
            TableCol(name='entering_date', caption=_('Entering date'),
                hidden=True, size=10),
            TableCol(name='comment', caption=_('Comment'), hidden=True),

            TableCol(name='customer', caption=_('Customer'), hidden=True),
            TableCol(name='customer_phone', caption=_('Phone'), hidden=True),

            TableCol(name='school_name', caption=_('School'), hidden=True, size=4),
            TableCol(name='school_form', caption=_('Form'), hidden=True, size=4),

            TableCol(name='surname_translit', caption=_('Surname translit'), size=10, hidden=True),
            TableCol(name='forename_translit', caption=_('Forename translit'), size=10, hidden=True),
            TableCol(name='patronymic_translit', caption=_('Patronymic translit'), size=10, hidden=True),
            ]
    model_object = model.Student
    item_tabs = [StudentsInGroupItemTab(), AgreementItemTab()]
    item_tabs1 = [DiscontCardTab(), MigrationsItemTab(), MarksItemTab(), PaymentItemTab()]
    view_fields = [
            'surname', 'forename', 'patronymic', 'email', 'gender', 'birthday',
            'enteringDate',
            'schoolName', 'schoolForm',
            'surname_translit', 'forename_translit', 'patronymic_translit',
            'comment',
            ]

    add_fields = [
        'surname', 'forename', 'patronymic', 'email', 'gender', 'birthday',
        'schoolName', 'schoolForm',
        'enteringDate',
        'comment',
        ]

    edit_fields = add_fields + ['surname_translit', 'forename_translit', 'patronymic_translit']

    def __init__(self, data_source=TableLookupDataSource('student_lookup')):
        LookupController.__init__(self,
            data_source=data_source,
            columns=self.lookup_columns,
            mass_actions_class=self.model_object,
            title=self.model_object.model_title,
            default_order_by='surname',
        )
        CRUDController.__init__(self, model_object=self.model_object)

        self.object_local_menu.extend((
            LocalMenuItem(caption=_('Transfer history'), href='transfer_history'),
            LocalMenuItem(caption=_('Finance history'), href='finance_history'),
        ))

    @expose(template="genshi:mnemoply.templates.student_transfer_history")
    def transfer_history(self, obj):
        return dict(obj=obj)
    transfer_history.expose_object = True

    @expose(template="genshi:mnemoply.templates.student_finance_history")
    def finance_history(self, obj, period=str(model.constants.getAcademicYear())):
        def list_cleanup(l, item):
            item_amount = l.count(item)
            for i in xrange(0, item_amount):
                l.remove(item)
            l.sort(key=lambda x: x.title)
            if item_amount:
                l.append(item)

        current_year_begin = model.constants.getAcademicYear()
        current_year_end = current_year_begin + 1

        if period.isdigit():
            from_my = MonthYear(9, int(period))
            to_my = MonthYear(8, int(period) + 1)
        else:
            assert period == 'All'
            from_my = MonthYear(obj.enteringDate.month, obj.enteringDate.year)
            to_my = MonthYear(8, current_year_end)

        from_date = from_my.get_begin_month()
        to_date = to_my.get_end_month()
        in_period = lambda x: (x >= from_date) and (x <= to_date)
        charge_date = lambda x: date(x.billingYear, x.billingMonth, 1)

        all_payment_records = list(model.PaymentRecord.selectBy(student=obj))
        all_charge_records = list(model.ChargeRecord.selectBy(student=obj))

        period_payment_records = [x for x in all_payment_records if in_period(x.date)]
        period_charge_records = [x for x in all_charge_records if in_period(charge_date(x))]

        sum = lambda xs, default: reduce(operator.add, xs, default)

        period_groups = list(set([x.getGroup() for x in period_payment_records + period_charge_records]))
        list_cleanup(period_groups, None)
        alltime_total_by_group = {}

        for g in period_groups:
            alltime_total_by_group[g] = \
                sum([x.amount for x in all_payment_records if x.getGroup() == g], Decimal(0)) - \
                sum([x.amount for x in all_charge_records if x.getGroup() == g], Decimal(0))

        # data create
        month_data_list = []
        for my in MonthYear.iterate(from_my, to_my):
            charge_records = [x for x in period_charge_records
                if (x.billingMonth == my.month) and (x.billingYear == my.year)]

            payment_records = [x for x in period_payment_records
                if (x.date >= my.get_begin_month()) and (x.date <= my.get_end_month())]

            by_group = {}
            for group in period_groups:
                payment = [x for x in payment_records if x.getGroup() == group]
                charge = [x for x in charge_records if x.getGroup() == group]

                by_group[group] = Wrapper(dict(
                    payment=payment,
                    charge=charge,
                    show=(len(payment) > 0) or (len(charge) > 0),
                ))

            month_data_list.append(Wrapper(dict(
                my=my,
                by_group=by_group,
                show=(len(charge_records) > 0) or (len(payment_records) > 0),
            )))

        # form create and output
        options = []
        for year in range(obj.enteringDate.year, current_year_begin + 1):
            options.append((year, "%d-%d" % (year, year + 1)))
        options.append(('All', 'All'))

        form = widgets.TableForm(name='Period',
            fields=[widgets.SingleSelectField('period', options=options)],
            submit_text=_("Select"))

        return dict(obj=obj,
                    from_my=from_my,
                    to_my=to_my,
                    period_groups=period_groups,
                    alltime_total_by_group=alltime_total_by_group,
                    month_data_list=month_data_list,
                    form=form)
    finance_history.expose_object = True

    @expose(template="genshi:mnemoply.templates.student_academ_problems")
    def academ_problems(self, obj):
        return dict(obj=obj, marks=obj.getMarks(only_bad_marks=True))
    academ_problems.expose_object = True

    def fill_lookup_data_defaults(self, data):
        is_parent_filled = LookupController.fill_lookup_data_defaults(self, data)
        if not is_parent_filled:
            office = "%02d-%04d" % \
                (identity.current.user.office.id, model.constants.getAcademicYear())
            args = {'flt_cache_groups': office, 'column': ['cache_groups', 'surname', 'forename']}
            data.update(args)

exposed = StudentController()
